package com.dhl.fin.api.service;

import cn.hutool.core.date.DateTime;
import com.dhl.fin.api.common.dto.QueryDto;
import com.dhl.fin.api.common.enums.ActionEnum;
import com.dhl.fin.api.common.exception.BusinessException;
import com.dhl.fin.api.common.service.CommonService;
import com.dhl.fin.api.common.util.DateUtil;
import com.dhl.fin.api.common.util.ObjectUtil;
import com.dhl.fin.api.common.util.StringUtil;
import com.dhl.fin.api.common.util.WebUtil;
import com.dhl.fin.api.dao.MyStatementDao;
import com.dhl.fin.api.domain.BankAccount;
import com.dhl.fin.api.domain.BankStatement;
import com.dhl.fin.api.domain.Family;
import com.dhl.fin.api.domain.LendRecord;
import com.dhl.fin.api.dto.BankStatementRequestDTO;
import com.dhl.fin.api.enums.BusinessTypeEnum;
import com.dhl.fin.api.enums.LendRecordStatusEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.dhl.fin.api.util.NumberGenerate;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author CuiJianbo
 * @since 2025/4/25
 */
@Service
public class LendRecordService extends CommonService<LendRecord> {

    @Autowired
    private BankStatementService bankStatementService;

    @Autowired
    private BankAccountService bankAccountService;

    @Autowired
    private FamilyService familyService;

    @Autowired
    private MyStatementDao myStatementDao;

    @Autowired
    private LendDailyInterestService lendDailyInterestService;
    @Autowired
    private BusinessRecordService businessRecordService;

    @Override
    public void beforeSave(LendRecord domain) throws Exception {

        //新增
        if (super.actionEnum.equals(ActionEnum.ADD)) {
            domain.setRecordNumber(NumberGenerate.generateLendRecordNumber());
            domain.setLendRecordStatus(LendRecordStatusEnum.REPAYING.getCode());
            domain.setLendBalance(domain.getLendMoneyAmount());
            domain.setCurrentPenaltyTotalMoney(0.0);
            domain.setCurrentTotalInterest(0.0);
        }

    }

    @Override
    public void afterSave(LendRecord domain) throws Exception {

        if (super.actionEnum.equals(ActionEnum.ADD)) {
            BankAccount bankAccount = bankAccountService.get(domain.getBankAccount().getId());

            BankStatementRequestDTO bankStatementRequestDTO = new BankStatementRequestDTO();
            bankStatementRequestDTO.setIncomeMoney(Double.parseDouble(domain.getLendMoneyAmount().toString()));
            bankStatementRequestDTO.setRemark(domain.getRemark());
            bankStatementRequestDTO.setCurrentBalance(bankAccount.getCurrentBalance());
            bankStatementRequestDTO.setType(BusinessTypeEnum.LEND_OUT_MONEY.getCode());
            bankStatementRequestDTO.setBankAccountId(bankAccount.getId());
            bankStatementRequestDTO.setTags(domain.getTag());
            bankStatementRequestDTO.setOperator(domain.getOperator());

            bankStatementService.outMoneyBankStatement(bankStatementRequestDTO);
        }

    }

    public List<BankAccount> queryAllChildLendRecord() throws Exception {
        String unicode = WebUtil.getStringParam("faUnicode");
        return bankAccountService.select(QueryDto.builder()
                .available()
                .addJoinDomain("lendRecords")
                .addWhere("lend_records.lend_record_status = 'REPAYING'")
                .addWhere("lend_records.remove = 0")
                .addWhere("family_unicode = '" + unicode + "'")
                .addOrder("lend_records.agreement_repay_date")
                .build());
    }


    public void repayLendMoney(Integer money, Long recordId, Long accountId) throws Exception {
        LendRecord lendRecord = get(recordId);
        Family loginUser = familyService.getLoginUserInfo();
        BankAccount bankAccount = bankAccountService.get(accountId);


        if (money.equals(lendRecord.getLendBalance())) { //全部还款

            LendRecord repayRecord = new LendRecord();
            repayRecord.setId(recordId);
            repayRecord.setLendRecordStatus(LendRecordStatusEnum.FINISHED.getCode());
            repayRecord.setActualRepayDate(DateUtil.getSysTime());
            repayRecord.setLendBalance(0);

            BankStatementRequestDTO lendStatementDTO = new BankStatementRequestDTO();
            lendStatementDTO.setOperator(loginUser.getMemberAlias());
            lendStatementDTO.setIncomeMoney(Double.parseDouble(money.toString()));
            lendStatementDTO.setBankAccountId(accountId);
            lendStatementDTO.setRemark("收到还款" + money + "元，借出记录号是" + lendRecord.getRecordNumber());
            lendStatementDTO.setCurrentBalance(bankAccount.getCurrentBalance());
            lendStatementDTO.setType(BusinessTypeEnum.LEND_RETURN_BACK_MONEY.getCode());

            BankStatementRequestDTO lendInterestStatementDTO = new BankStatementRequestDTO();
            double totalInterest = lendRecord.getCurrentPenaltyTotalMoney() + lendRecord.getCurrentTotalInterest(); //违约罚息 + 借出利息
            double newCurrentBalance = lendStatementDTO.getCurrentBalance() + lendStatementDTO.getIncomeMoney();
            lendInterestStatementDTO.setOperator(loginUser.getMemberAlias());
            lendInterestStatementDTO.setIncomeMoney(totalInterest);
            lendInterestStatementDTO.setBankAccountId(accountId);
            lendInterestStatementDTO.setRemark("获得利息" + totalInterest + "元，借出记录号是" + lendRecord.getRecordNumber());
            lendInterestStatementDTO.setType(BusinessTypeEnum.LEND_INTEREST_MONEY.getCode());
            lendInterestStatementDTO.setCurrentBalance(newCurrentBalance);

            //更新借出记录状态为已还完
            updateBySelective(repayRecord);

            //收回本金，把本金记录到账户流水
            BankStatement bankStatement = bankStatementService.incomeBankStatement(lendStatementDTO);

            //记录一条业务数据
            businessRecordService.addBusinessRecord(bankStatement);

            if (totalInterest > 0) {

                //获取利息，把利息记录账户流水
                bankStatementService.incomeBankStatement(lendInterestStatementDTO);

                //更新微行卡的总利息收益金额
                Double newTotalInterest = bankAccount.getTotalInterestIncome() + totalInterest;
                bankAccountService.updateFieldById(accountId, "totalInterestIncome", newTotalInterest);
            }

        } else {  //部分还款
            int newLendBalance = lendRecord.getLendBalance() - money;
            if (newLendBalance < 0) {
                throw new BusinessException("还款金额过大");
            }
            BankStatementRequestDTO bankStatementRequestDTO = new BankStatementRequestDTO();
            bankStatementRequestDTO.setOperator(loginUser.getMemberAlias());
            bankStatementRequestDTO.setIncomeMoney(Double.parseDouble(money.toString()));
            bankStatementRequestDTO.setBankAccountId(accountId);
            bankStatementRequestDTO.setRemark("收到部分还款,借出记录号是" + lendRecord.getRecordNumber());
            bankStatementRequestDTO.setCurrentBalance(bankAccount.getCurrentBalance());
            bankStatementRequestDTO.setType(BusinessTypeEnum.LEND_RETURN_BACK_MONEY.getCode());

            //更新借出记录的还款余额
            updateFieldById(recordId, "lendBalance", newLendBalance);

            //记录账户流水
            BankStatement bankStatement = bankStatementService.incomeBankStatement(bankStatementRequestDTO);

            //记录一条业务数据
            businessRecordService.addBusinessRecord(bankStatement);

        }
    }

    public Integer getTotalLendMoney(Long accountId) {
        try {
            return select(QueryDto.builder()
                    .available()
                    .addWhere("bank_account_id = " + accountId)
                    .addWhere("lend_record_status = '" + LendRecordStatusEnum.REPAYING.getCode() + "'")
                    .build())
                    .stream()
                    .map(LendRecord::getLendBalance)
                    .filter(Objects::nonNull)
                    .reduce(0, Integer::sum);
        } catch (Exception e) {
            return 0;
        }
    }

    @Override
    public void afterGet(LendRecord domain) throws Exception {
        String status = domain.getLendRecordStatus();
        if (StringUtil.isNotEmpty(status)) {
            LendRecordStatusEnum statusEnum = LendRecordStatusEnum.getLendRecordStatusEnum(status);
            if (ObjectUtil.notNull(statusEnum)) {
                domain.setLendRecordStatusName(statusEnum.getName());
            }
        }

        if (ObjectUtil.notNull(domain.getActualRepayDate())) {
            domain.setActualRepayDateStr(DateUtil.getFullTime(domain.getActualRepayDate()));
        }

    }

    @Override
    public void afterPageQuery(List<LendRecord> datas) throws Exception {
        for (LendRecord data : datas) {
            String status = data.getLendRecordStatus();
            if (StringUtil.isNotEmpty(status)) {
                LendRecordStatusEnum statusEnum = LendRecordStatusEnum.getLendRecordStatusEnum(status);
                if (ObjectUtil.notNull(statusEnum)) {
                    data.setLendRecordStatusName(statusEnum.getName());
                }
            }
        }
    }

    public List<String> getLendRecordYearMonth(DateTime startTime,String familyCode) {
        return myStatementDao.queryLendRecordDateTime(DateUtil.getTime(startTime),familyCode);
    }

    public List<LendRecord> queryLendRecord(String yearmonth, Long bankAccountId) throws Exception {
        List<LendRecord> datas = select(QueryDto.builder()
                .available()
                .addWhere("bank_account_id = " + bankAccountId)
                .addWhere("DATE_FORMAT(create_time, '%Y-%m') = '" + yearmonth + "'")
                .build());

        for (LendRecord data : datas) {
            String status = data.getLendRecordStatus();
            if (StringUtil.isNotEmpty(status)) {
                LendRecordStatusEnum statusEnum = LendRecordStatusEnum.getLendRecordStatusEnum(status);
                if (ObjectUtil.notNull(statusEnum)) {
                    data.setLendRecordStatusName(statusEnum.getName());
                }
            }
        }

        return datas;
    }

    @Transactional(rollbackFor = Exception.class)
    public void calculateDailyLendInterest() throws Exception {
        List<LendRecord> lendRecords = select(QueryDto.builder()
                .available()
                .addWhere("lend_record_status = '" + LendRecordStatusEnum.REPAYING.getCode() + "'")
                .addWhere("lend_balance > 0")
                .build());

        for (LendRecord lendRecord : lendRecords) {
            double todayInterest = lendRecord.getLendBalance() * lendRecord.getLendYearRate() / 365;
            double todayPenaltyInterest = 0.0;

            Date nowDate = DateUtil.getDate(DateUtil.getTime(DateUtil.getSysDate()));
            if (lendRecord.getAgreementRepayDate().compareTo(nowDate) < 0) {
                todayPenaltyInterest = lendRecord.getLendBalance() * lendRecord.getPenaltyYearRate() / 365;
            }

            //新增一条每天借出利息数据
            lendDailyInterestService.addLendDailyInterest(todayInterest, todayPenaltyInterest, lendRecord.getLendBalance(), lendRecord);

            double newTotalInterest = lendRecord.getCurrentTotalInterest() + todayInterest;
            double newTotalPenaltyInterest = lendRecord.getCurrentPenaltyTotalMoney() + todayPenaltyInterest;

            LendRecord updateRecord = new LendRecord();
            updateRecord.setId(lendRecord.getId());
            updateRecord.setCurrentTotalInterest(newTotalInterest);
            updateRecord.setCurrentPenaltyTotalMoney(newTotalPenaltyInterest);

            //更新借出记录的当前利息值
            updateBySelective(updateRecord);

        }

    }

}
